#!/usr/bin/perl

# The purpose of this script is to automatically generate
# read/write/begin/commit methods when STM_INST_SWITCHADAPT is defined


# Start by printing a copyright and a warning
print "/**
 *  Copyright (C) 2011
 *    University of Rochester Department of Computer Science
 *      and
 *    Lehigh University Department of Computer Science and Engineering
 *
 *  License: Modified BSD
 *           Please see the file LICENSE.RSTM for licensing information
 */

/**
 *  Note: This file is automatically generated.  You should not modify
 *  it directly.
 */

";

print "
/**
 *  This file only has meaning when STM_INST_SWITCHADAPT is defined, but
 *  rather than put conditionals in the makefile, we guard the contents
 *  of the file.
 */
#ifdef STM_INST_SWITCHADAPT
";

# now print the includes that we will need
print "
#include \"../algs/algs.hpp\"
#include \"../Diagnostics.hpp\"
";

# put all declarations in namespace stm
print "
namespace stm
{

";

# It is expected that the command line contains the names of all algorithms,
# and nothing else.  Nonetheless, we'll copy the array to one with a better
# name
@algs = @ARGV;

# We'll discuss the generation of the tmbegin function in detail.  From
# there, the rest are easy.
#
# The basic structure of tmbegin is that it has a big switch statement, which
# calls exactly one of the many algorithms Begin functions, based on the
# value of curr_policy.ALG_ID.
#
# Unfortunately, there is no header file that declares the Begin function for
# each of the algorithms.  Thus we need to pre-declare these functions first.
# For algorithm X, the declaration of the begin function is void
# XBegin(TX_LONE_PARAMETER).

# Step 1: declare the Begin functions:
foreach my $alg (@algs) {
    print "  void ${alg}Begin(TX_LONE_PARAMETER);\n"
}

# Step 2: generate the tmbegin function prelude
print "
  void tmbegin(TX_LONE_PARAMETER)
  {
      switch (curr_policy.ALG_ID)
      {
";

# Step 3: generate the cases
foreach my $alg (@algs) {
print "        case ${alg}:
          ${alg}Begin(TX_LONE_ARG);
          break;\n"
}

# Step 4: generate the tmbegin function epilogue
print "        default:
          UNRECOVERABLE(\"Unrecognized Algorithm\");
      }
  }

";

# Now we can do tmcommit.  The only difference here is that the function
# declaration is slightly more complex

foreach my $alg (@algs) {
    print "  TM_FASTCALL void ${alg}Commit(TX_LONE_PARAMETER);\n"
}

print "
  void tmcommit(TX_LONE_PARAMETER)
  {
      switch (curr_policy.ALG_ID)
      {
";

foreach my $alg (@algs) {
print "        case ${alg}:
          ${alg}Commit(TX_LONE_ARG);
          break;\n"
}

print "        default:
          UNRECOVERABLE(\"Unrecognized Algorithm\");
      }
  }

";

# tmwrite takes parameters, but otherwise is the same as tmcommit

foreach my $alg (@algs) {
    print "  TM_FASTCALL void ${alg}Write(TX_FIRST_PARAMETER STM_WRITE_SIG(addr,val,));\n"
}

print "
  void tmwrite(TX_FIRST_PARAMETER STM_WRITE_SIG(addr,val,))
  {
      switch (curr_policy.ALG_ID)
      {
";

foreach my $alg (@algs) {
print "        case ${alg}:
          ${alg}Write(TX_FIRST_ARG addr, val);
          break;\n"
}

print "        default:
          UNRECOVERABLE(\"Unrecognized Algorithm\");
      }
  }

";

# tmread takes parameters and also has a return value

foreach my $alg (@algs) {
    print "  TM_FASTCALL void* ${alg}Read(TX_FIRST_PARAMETER STM_READ_SIG(addr,));\n"
}

print "
  void* tmread(TX_FIRST_PARAMETER STM_READ_SIG(addr,))
  {
      switch (curr_policy.ALG_ID)
      {
";

foreach my $alg (@algs) {
print "        case ${alg}:
          return ${alg}Read(TX_FIRST_ARG addr);
          break;\n"
}

print "        default:
          UNRECOVERABLE(\"Unrecognized Algorithm\");
      }
      return NULL;
  }

";

# close out the namespace and the #define guard
print "
} // namespace stm

#endif // STM_INST_SWITCHADAPT
";
